
package com.idealighter.game.games.foursshop.manager;

import com.alibaba.fastjson.JSONObject;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.chat.manager.ChatMsgMgr;
import com.idealighter.game.core.common.Game;
import com.idealighter.game.core.constant.BoolInteger;
import com.idealighter.game.core.constant.notice.NoticeType;
import com.idealighter.game.dictionary.dic.FoursShopRoomDic;
import com.idealighter.game.dictionary.dic.FoursShopRoomTypeDic;
import com.idealighter.game.dictionary.dic.GameNoticeDic;
import com.idealighter.game.dictionary.domain.FoursLogPlanDomain;
import com.idealighter.game.dictionary.domain.FoursShopRoomDomain;
import com.idealighter.game.dictionary.domwrapper.GameNoticeDomainWrapper;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.games.common.AbstractRoom;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.RoomState;
import com.idealighter.game.games.foursshop.dto.BankerRanker;
import com.idealighter.game.games.foursshop.dto.BetsInfo;
import com.idealighter.game.games.foursshop.dto.FoursIconMultiple;
import com.idealighter.game.games.foursshop.dto.RoomInfo;
import com.idealighter.game.games.foursshop.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.foursshop.message.ResBalanceMsg;
import com.idealighter.game.games.foursshop.message.ResBankerInfoMsg;
import com.idealighter.game.games.foursshop.message.ResBankerListMsg;
import com.idealighter.game.games.foursshop.message.ResBetResultMsg;
import com.idealighter.game.games.foursshop.message.ResBetsChangeMsg;
import com.idealighter.game.games.foursshop.message.ResBillMsg;
import com.idealighter.game.games.foursshop.message.ResCancelBankerMsg;
import com.idealighter.game.games.foursshop.message.ResCancelOnBankerMsg;
import com.idealighter.game.games.foursshop.message.ResChipsChangeMsg;
import com.idealighter.game.games.foursshop.message.ResClearBetMsg;
import com.idealighter.game.games.foursshop.message.ResContinueBetMsg;
import com.idealighter.game.games.foursshop.message.ResEnterGameHallMsg;
import com.idealighter.game.games.foursshop.message.ResEnterRoomMsg;
import com.idealighter.game.games.foursshop.message.ResEnterTableMsg;
import com.idealighter.game.games.foursshop.message.ResExitRoomMsg;
import com.idealighter.game.games.foursshop.message.ResExitTableMsg;
import com.idealighter.game.games.foursshop.message.ResFastEnterTableMsg;
import com.idealighter.game.games.foursshop.message.ResMosaicGoldMsg;
import com.idealighter.game.games.foursshop.message.ResMosaicMsg;
import com.idealighter.game.games.foursshop.message.ResMultipleMsg;
import com.idealighter.game.games.foursshop.message.ResOnBankerMsg;
import com.idealighter.game.games.foursshop.message.ResRandCarResultMsg;
import com.idealighter.game.games.foursshop.message.ResRobtCarAreaMsg;
import com.idealighter.game.games.foursshop.message.ResTimeMsg;
import com.idealighter.game.games.foursshop.struct.FoursShopRoom;
import com.idealighter.game.games.foursshop.struct.FoursShopSeat;
import com.idealighter.game.games.foursshop.struct.FoursShopTable;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.notice.manager.NoticeMsgMgr;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;
import com.idealighter.utils.code.RandCodeUtil;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 4s店传消息管理 .
 */
@Singleton
public class FoursShopMsgMgr {
  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private FoursShopDataMgr dataMgr;
  @Inject
  private FoursShopRoomDic roomDic;
  @Inject
  private FoursShopRoomTypeDic roomTypeDic;
  @Inject
  private NoticeMsgMgr msgMgr;
  @Inject
  private GameNoticeDic gameNoticeDic;
  @Inject
  private ChatMsgMgr chatMsgMgr;

  /**
   * 发送进入大厅消息 .
   * 
   * @param player 玩家.
   */
  public void sendEnterGameHallMsg(Player player) {
    ResEnterGameHallMsg msg = new ResEnterGameHallMsg();

    Collection<FoursShopRoom> rooms = dataMgr.rooms();
    for (FoursShopRoom room : rooms) {
      FoursShopRoomDomain roomDomain = roomDic.map().get(room.getId().intValue());
      if (roomDomain.getIsActive() != 1) {
        continue;
      }
      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();

      roomTypeDetailInfo.setType(roomDomain.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDomain.getType()).getName());

      RoomInfo roomInfo = new RoomInfo();
      roomInfo.setRoomId(room.getId().intValue());
      roomInfo.setName(roomDomain.getName());
      roomInfo.setType(roomDomain.getType());
      roomInfo.setMaxNum(roomDomain.getMaxNum());
      roomInfo.setFree(roomDomain.getFree());
      roomInfo.setGeneral(roomDomain.getGeneral());
      roomInfo.setCrowded(roomDomain.getCrowded());
      // roomInfo.setFull(roomDomain.getFull());
      roomInfo.setLower(roomDomain.getLower());
      roomInfo.setUpper(roomDomain.getUpper());
      roomInfo.setProportionGold(roomDomain.getProportionGold());
      roomInfo.setProportionChips(roomDomain.getProportionChips());
      roomInfo.setTabble(roomDomain.getTable());
      roomInfo.setAfee(roomDomain.getAfee());
      roomInfo.setInType(roomDomain.getInType());
      roomInfo.setPlayerNum(room.getPlayers().size());
      roomInfo.setStatus(roomStatus(room).desc);
      roomInfo.setDisplayNames(roomDomain.getDisplays());
      roomInfo.setPlaceHolder(roomDomain.getPlaceHolder());
      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }

    msgWriter.writeMsg(player, msg);
  }

  /**
   * 房间状态，空闲,普通,拥挤,爆满 .
   * 
   * @param room .
   * @return
   */
  private RoomState roomStatus(FoursShopRoom room) {
    int playersNum = room.getPlayers().size();
    FoursShopRoomDomain roomDom = roomDic.map().get(room.getId().intValue());

    if (playersNum < roomDom.getMaxNum() * roomDom.getFree() / 100) {
      return RoomState.IDLE;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getGeneral() / 100) {
      return RoomState.GENERAL;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getCrowded() / 100) {
      return RoomState.CROWD;
    } else {
      return RoomState.FULL;
    }
  }

  /**
   * 发送进入房间消息 .
   * 
   * @param player 玩家.
   */
  public void sendEnterRoomMsg(Player player) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    for (AbstractTable table : player.curRoom.tables()) {
      msg.getTables().add(table.tableInfo());
    }
    msg.setMembers(player.curRoom.memInfos());
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送进入桌子消息 .
   * 
   * @param player 玩家.
   * @param table .
   */
  public void sendEnterTableMsg(Player player, AbstractTable table) {
    ResEnterTableMsg msg = new ResEnterTableMsg();
    AbstractRoom room = table.room();
    List<MemInfo> mems = new ArrayList<>();
    for (Long playerId : table.players()) {
      mems.add(room.memInfo(playerId));
    }
    msg.setMems(mems);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送兑换筹码消息 .
   * 
   * @param seat 座位信息.
   */
  public void sendChipsChangeMsg(FoursShopSeat seat) {
    ResChipsChangeMsg msg = new ResChipsChangeMsg();
    msg.setChips(seat.getTotalChips());
    msg.setPlayerId(seat.getPlayerId());
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送退出房间消息 .
   * 
   * @param player 玩家.
   * @param res 0:退出成功,1:在牌桌中退出失败
   */
  public void sendExitRoomMsg(Player player, int res) {
    ResExitRoomMsg msg = new ResExitRoomMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送庄家信息给玩家(立刻刷新) .
   *
   * @param player 玩家.
   * @param table .
   */
  public void sendBankerInfo(Player player, FoursShopTable table) {
    ResBankerInfoMsg msg = new ResBankerInfoMsg();
    msg.setImmediately(0);
    if (table.bankerPlayerId != 0) {
      FoursShopSeat seat = dataMgr.getPlayerSeat(table.bankerPlayerId);
      if (seat == null) {
        return;
      }
      msg.setPlayerId((int) table.bankerPlayerId);
      msg.setName(seat.getPlayerName());
      msg.setGold(seat.getTotalChips());
      msg.setCount(table.count);
      msg.setScore(0);
    } else {
      msg.setPlayerId(0);
      msg.setName("系统开店");
      msg.setScore(0);
      msg.setGold(0);
      msg.setCount(table.count);
    }
    if (player == null) {
      msg.setCount(0);
      msg.setScore(0);
      sendTablePlayersMsg(table, msg);
    } else {
      msgWriter.writeMsg(player, msg);
    }
  }

  /**
   * 庄家信息改变(非立刻刷新) .
   *
   * @param table .
   */
  public void sendBankerInfoUpdate(FoursShopTable table) {
    ResBankerInfoMsg msg = new ResBankerInfoMsg();
    msg.setImmediately(1);
    if (table.bankerPlayerId != 0) {
      FoursShopSeat seat = dataMgr.getPlayerSeat(table.bankerPlayerId);
      if (seat == null) {
        return;
      }
      msg.setPlayerId((int) table.bankerPlayerId);
      msg.setName(seat.getPlayerName());
      msg.setGold(seat.getTotalChips());
      msg.setCount(table.count);
      msg.setScore(table.score);
    } else {
      msg.setPlayerId(0);
      msg.setName("系统开店");
      msg.setScore(table.score);
      msg.setGold(0);
      msg.setCount(table.count);
    }
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 发送申请庄家列表给玩家 .
   */
  public void sendBankerList(Player player, FoursShopTable table) {
    ResBankerListMsg msg = new ResBankerListMsg();
    for (Object obj : table.bankers) {
      if (!(obj instanceof Long)) {
        continue;
      }
      BankerRanker banker = new BankerRanker();
      banker.setId(Integer.parseInt(obj.toString()));
      banker.setName(dataMgr.getPlayerSeat((Long) obj).getPlayerName());
      banker.setChips(dataMgr.getPlayerSeat((Long) obj).getTotalChips());
      msg.getBanker().add(banker);
    }
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送快速进入结果消息 .
   * 
   * @param player 玩家.
   * @param res 0:成功,1:没有空位置
   */
  public void sendFastEnterTableMsg(Player player, int res) {
    ResFastEnterTableMsg msg = new ResFastEnterTableMsg();
    msg.setRes(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送退出桌子消息.
   * 
   * @param seat 座位信息.
   */
  public void sendExitTableMsg(FoursShopSeat seat) {
    ResExitTableMsg msg = new ResExitTableMsg();
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 发送结算消息 .
   * 
   * @param seat 座位信息.
   * @param res 0:成功,1:没有可结算筹码
   */
  public void sendBillMsg(FoursShopSeat seat, int res) {
    ResBillMsg msg = new ResBillMsg();
    msg.setRes(res);
    msgWriter.writeMsg(seat.getPlayerId(), msg);
  }

  /**
   * 通知客户端计时.
   */
  public void sendTime(FoursShopTable table, int state, int time) {
    ResTimeMsg msg = new ResTimeMsg();
    msg.setState(state);
    msg.setTime(time);
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 告知刚进入房间的玩家当前的状态和倒计时间.
   */
  public void sendTimeToEnterPlayer(FoursShopTable table, Player player) {
    ResTimeMsg msg = new ResTimeMsg();
    msg.setState(table.state);
    msg.setTime((int) table.stepFuture.getDelay(TimeUnit.SECONDS) > 0
        ? (int) table.stepFuture.getDelay(TimeUnit.SECONDS)
        : 0);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 返回玩家上庄结果 .
   *
   * @param player 玩家.
   */
  public void sendOnBanker(Player player, int res, FoursShopTable table) {
    ResOnBankerMsg msg = new ResOnBankerMsg();
    table.bankers.stream().filter(obj -> obj instanceof Long).forEach(obj -> {
      BankerRanker banker = new BankerRanker();
      banker.setId(Integer.parseInt(obj.toString()));
      banker.setName(dataMgr.getPlayerSeat(obj).getPlayerName());
      banker.setChips(dataMgr.getPlayerSeat(obj).getTotalChips());
      msg.getBankers().add(banker);
    });
    msg.setResult(res);
    if (player != null) {
      msgWriter.writeMsg(player, msg);
    }
    if (res == 0) { // 庄家上庄成功向房间里面的玩家广播
      sendTablePlayersMsg(table, msg);
    }
  }

  /**
   * 取消上庄排队 .
   *
   * @param player 玩家.
   * @param table .
   * @param res 上庄结果0：成功，1：失败.
   */

  public void sendcancleBanker(Player player, FoursShopTable table, int res) {
    ResCancelOnBankerMsg msg = new ResCancelOnBankerMsg();
    for (Object obj : table.bankers) {
      if (obj == null) {
        continue;
      }
      if (obj instanceof Long) {
        BankerRanker banker = new BankerRanker();
        banker.setId(Integer.parseInt(obj.toString()));
        banker.setName(dataMgr.getPlayerSeat((Long) obj).getPlayerName());
        banker.setChips(dataMgr.getPlayerSeat((Long) obj).getTotalChips());
        msg.getBanker().add(banker);
      }
    }
    msg.setResult(res);
    msgWriter.writeMsg(player, msg);
    if (res == 0) {
      sendOnBanker(player, res, table);
    }
  }

  /**
   * 返回下庄结果 .
   *
   * @param player 玩家.
   * @param res 下注结果返回0：成功，1：失败.
   */
  public void sendCancelBanker(Player player, int res) {
    ResCancelBankerMsg msg = new ResCancelBankerMsg();
    msg.setResult(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 玩家下注 .
   *
   * @param player 玩家.
   */
  public void sendDoBet(Player player, int res) {
    ResBetResultMsg msg = new ResBetResultMsg();
    msg.setResult(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 自动续注结果返回 .
   *
   * @param res 续押返回：0成功,1失败.
   */
  public void sendContineBet(Player player, int res) {
    ResContinueBetMsg msg = new ResContinueBetMsg();
    msg.setResult(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 清空下注返回 .
   *
   * @param player 玩家.
   * @param res 清空下注：0成功,1失败.
   */
  public void sendClearBet(Player player, int res) {
    ResClearBetMsg msg = new ResClearBetMsg();
    msg.setResult(res);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 总下注变化.
   */
  public void sendBetsChange(FoursShopTable table, Player player) {
    ResBetsChangeMsg msg = new ResBetsChangeMsg();
    table.getTotalBetInfo().stream().filter(betsInfo -> betsInfo != null).forEach(betsInfo -> {
      BetsInfo info = new BetsInfo();
      info.setCarId(betsInfo.getCarId());
      info.setBet(betsInfo.getBet());
      msg.getBestInfo().add(info);
    });
    if (player == null) {
      sendTablePlayersMsg(table, msg);
    } else {
      msgWriter.writeMsg(player, msg);
    }
  }

  /**
   * 发送随机汽车图标和倍率的结果.
   * 
   * @param table .
   * @param carId .
   * @param rate .
   * @param startIndex .
   * @param rewardTime .
   */

  public void sendsRandCarResult(FoursShopTable table, int carId, int rate, int startIndex,
      int rewardTime) {
    ResRandCarResultMsg msg = new ResRandCarResultMsg();
    msg.setCarId(carId);
    msg.setRate(rate);
    msg.setStartIndex(startIndex);
    msg.setRewardTime(rewardTime);
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 玩家进入房间发送开出的倍率(防止玩家在进入房间的时候，该信息已经发过导致客户端没法显示正确的信息) .
   *
   * @param player 玩家.
   * @param table .
   */
  public void sendCardResult(Player player, FoursShopTable table) {
    ResRandCarResultMsg msg = new ResRandCarResultMsg();
    msg.setCarId(table.getCarId());
    msg.setRate(table.getRate());
    msg.setStartIndex(table.startIndex);
    msg.setRewardTime(table.rewardTime);
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 玩家进入发送当前局的汽车图标倍率 .
   *
   * @param plans .
   */
  public void sendFoursShopIcons(Player player, List<FoursLogPlanDomain> plans) {
    ResMultipleMsg msg = new ResMultipleMsg();
    plans.forEach(val -> {
      FoursIconMultiple fms = new FoursIconMultiple();
      fms.setCardId(val.getCarid());
      fms.setName(val.getName());
      fms.setRate(val.getRate());
      msg.getFoursPlan().add(fms);
    });
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 开始游戏前发送本局的汽车图标倍率 .
   *
   * @param table .
   * @param plans .
   */
  public void sendrandomFoursShopIcons(FoursShopTable table, List<FoursLogPlanDomain> plans) {
    ResMultipleMsg msg = new ResMultipleMsg();
    plans.forEach(val -> {
      FoursIconMultiple fms = new FoursIconMultiple();
      fms.setCardId(val.getCarid());
      fms.setName(val.getName());
      fms.setRate(val.getRate());
      msg.getFoursPlan().add(fms);
    });
    sendTablePlayersMsg(table, msg);
  }

  /**
   * 玩家结算结果 .
   *
   * @param table .
   */
  public void sendBalance(FoursShopTable table, long bankearn, long bankerTotalChips) {
    table.seats.stream().filter(seat -> seat.getPlayerId() > 0).forEach(seat -> {
      ResBalanceMsg msg = new ResBalanceMsg();
      msg.setBankerEarn(bankearn);
      msg.setBankerTotalChips(bankerTotalChips);
      msg.setMosaicGold(table.mosaicGold);
      msg.setBillChips(seat.billChips);
      msg.setTotalChips(seat.getTotalChips());
      msgWriter.writeMsg(seat.getPlayerId(), msg);
      if (table.mosaicGoldCount >= 3) {
        sendMosaic(seat.getPlayerId(), seat.mosaci);
      }
    });

    sendBankerInfoUpdate(table);
  }

  /**
   * 彩金池消息 .
   *
   * @param playerId 玩家id.
   * @param mosaicNum .
   */
  public void sendMosaic(long playerId, long mosaicNum) {
    ResMosaicMsg msg = new ResMosaicMsg();
    msg.setNum(mosaicNum);
    msgWriter.writeMsg(playerId, msg);

  }

  /**
   * 发送结算信息.
   * 
   * @param room .
   * @param msg .
   */

  public void sendPlayerBalance(FoursShopRoom room, ResMessage msg) {
    room.getPlayers().forEach(p -> msgWriter.writeMsg(p, msg));
  }

  /**
   * 向同房间的玩家(包括自己)发送消息 .
   * 
   * @param room .
   * @param msg .
   */
  public void sendRoomPlayersMsg(FoursShopRoom room, ResMessage msg) {
    room.getPlayers().forEach(p -> msgWriter.writeMsg(p, msg));
  }

  /**
   * 单独发送给机器人 .
   *
   * @param table .
   */
  public void sendRobtBetCar(FoursShopTable table) {
    ResRobtCarAreaMsg msg = new ResRobtCarAreaMsg();
    if (table.mosaicGoldCount == 2) {
      msg.getCarId().add(table.getCarId());
    }
    int randNum = RandCodeUtil.random(5, 7);
    while (true) {
      int cardId = RandCodeUtil.random(1, 8);
      if (!msg.getCarId().contains(cardId)) {
        msg.getCarId().add(cardId);
      }
      if (msg.getCarId().size() == randNum) {
        break;
      }
    }
    sendTablePlayersMsg(table, msg);

  }

  /**
   * 进入游戏发送彩金池数量 .
   *
   * @param player 玩家.
   * @param mosaicGold .
   */
  public void sendMosaicGold(Player player, long mosaicGold) {
    ResMosaicGoldMsg msg = new ResMosaicGoldMsg();
    msg.setMosaicGold(mosaicGold);
    msgWriter.writeMsg(player, msg);

  }

  /**
   * 向房间里面的玩家广播消息 .
   *
   * @param table .
   * @param msg .
   */
  private void sendTablePlayersMsg(FoursShopTable table, ResMessage msg) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 如果满足条件发送公告 .
   * 
   * @param playerName .
   * @param carId .
   * @param chips . 赢得筹码
   * @param mosaci .
   */
  public void sendedNotice(String playerName, int carId, long chips, long mosaci) {

    for (GameNoticeDomainWrapper dom : gameNoticeDic.getGameDoms().get(Game.FOURS_SHOP.getType())) {
      JSONObject conditionData = dom.conditionData();
      // 公告条件牌型
      Integer conditioncardId = conditionData.getInteger("id");
      // 公告条件赢得最小筹码
      Integer conditionMinChips = conditionData.getInteger("minChips");

      if ((conditioncardId == 0 && mosaci >= conditionMinChips)
          || (carId == conditioncardId && chips >= conditionMinChips)) {
        String sendContent = MessageFormat.format(dom.getContent(), playerName, chips);
        if (dom.getMarqueeShow() == BoolInteger.TRUE) { // 跑马灯公告
          msgMgr.sendMarqueeNoticeMsg(sendContent, NoticeType.GAME, dom.getInterval(),
              dom.getTimes(), dom.getColor());
        }

        if (dom.getChatShow() == BoolInteger.TRUE) { // 聊天公告
          chatMsgMgr.sendSysNoticeMsg(sendContent);
        }
      }
    }
  }
}
